﻿using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Routing;

namespace Songhay.Web.Mvc.Constraints
{
    /// <summary>
    /// Constrains a Route with a not-equal constraint.
    /// </summary>
    /// <remarks>
    /// This class is an alternative to using “negative look-behind” zero-width assertion regular expressions.
    /// </remarks>
    public class NotEqualConstraint : IRouteConstraint
    {
        /// <summary>
        /// Constructs a Route Constraint of one possible match.
        /// </summary>
        /// <param name="match">One possible match</param>
        public NotEqualConstraint(string match)
        {
            this._matches.Add(match);
        }

        /// <summary>
        /// Constructs a Route Constraint of one possible match.
        /// </summary>
        /// <param name="matches">An array of possible matches</param>
        public NotEqualConstraint(string[] matches)
        {
            this._matches.AddRange(matches);
        }

        /// <summary>
        /// Constructs a Route Constraint of one possible match.
        /// </summary>
        /// <param name="match">One possible match</param>
        /// <param name="blockLegacyRoutes">When <c>true</c> constrain all <c>*.mvc</c> routes.</param>
        public NotEqualConstraint(string match, bool blockLegacyRoutes)
        {
            this._blockLegacyRoutes = blockLegacyRoutes;
            this._matches.Add(match);
        }

        /// <summary>
        /// Constructs a Route Constraint of one possible match.
        /// </summary>
        /// <param name="matches">An array of possible matches</param>
        /// <param name="blockLegacyRoutes">When <c>true</c> constrain all <c>*.mvc</c> routes.</param>
        public NotEqualConstraint(string[] matches, bool blockLegacyRoutes)
        {
            this._blockLegacyRoutes = blockLegacyRoutes;
            this._matches.AddRange(matches);
        }

        #region IRouteConstraint Members

        /// <summary>
        /// Implements <see cref="System.Web.Routing.IRouteConstraint.Match"/>.
        /// </summary>
        /// <param name="httpContext">The <see cref="System.Web.HttpContextBase"/></param>
        /// <param name="route">The <see cref="System.Web.Routing.Route"/></param>
        /// <param name="parameterName">The constrained parameter (e.g.: <c>controller</c>, <c>action</c>, <c>id</c>)</param>
        /// <param name="values">The <see cref="System.Web.Routing.RouteValueDictionary"/></param>
        /// <param name="routeDirection">The <see cref="System.Web.Routing.RouteDirection"/></param>
        /// <returns>Returns <c>true</c> when no matches with the constrained parameter are found among the Route values.</returns>
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            string routeValue = values[parameterName].ToString();

            if(this._blockLegacyRoutes && routeValue.Contains(".mvc")) return false;

            bool areNotEqual = true;

            foreach(string match in this._matches)
            {
                bool areEqual = (string.Compare(routeValue, match, true) == 0);
                if(areEqual) return areNotEqual = false;
            }

            return areNotEqual;
        }

        #endregion

        private bool _blockLegacyRoutes = false;
        private List<string> _matches = new List<string>();
    }
}
